package com.xinlang.excel;


import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;


/**
 * ��ʾReport��ÿһҳ��ݵ���ݽṹ���൱��Excel�е�Sheet��
 * 
 * @param <X>
 * @param <Y>
 * @param <Z>
 */
// �У��У�ֵ
public class RawTable<X, Y, Z> {

	protected String title; // ���Ӧ�ı���
	protected String rowName = "-"; // rowһ�ж�Ӧ������
	protected List<BufferedImage> images; // ÿ�ű�ɺ���������ͼƬ

	protected Set<Y> columnNames = new TreeSet<Y>();
	protected List<Y> columnList = new ArrayList<Y>();

	protected List<Pair<String, X>> orderBy = null; // ����ĳһ������
	protected Y orderByColumnName = null; // ���������
	protected String nullValueOrderKey = ""; // ֵΪ�յĵ�Ԫ���Ӧ�������key

	// �������ģ��
	protected Map<X, Map<Y, Z>> rows = new TreeMap<X, Map<Y, Z>>();
	
	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	/**
	 * ����ĳ������
	 * 
	 * @param columnName
	 */
	public void orderBy(Y columnName) {
		orderBy(columnName, true); // Ĭ�ϰ�����������
	}

	private String valueToString(Z value) {
		if(value==null) {
			return nullValueOrderKey; 
		}
		if(value instanceof Double) { 
			return String.format("%10f", value);
		}
		if(value instanceof Long || value instanceof Integer) {
			return String.format("%10d", value);
		}
		return value.toString();
	}
	
	public void orderBy(Y columnName, boolean isAscending) {
		if (!columnNames.contains(columnName)) {
			// ��������
			orderBy = null;
			return;
		}

		orderBy = new ArrayList<Pair<String, X>>();
		for (Map.Entry<X, Map<Y, Z>> row : rows.entrySet()) {
			X x = row.getKey();
			Map<Y, Z> map = row.getValue();
			Z value = map.get(columnName);
			orderBy.add(new Pair<String, X>(valueToString(value), x));
		}

		if (!isAscending) {
			// ����orderBy�е�value����
			Collections.sort(orderBy, Collections.reverseOrder());
		} else {
			// ����orderBy�е�value��������
			Collections.sort(orderBy);
		}

		this.orderByColumnName = columnName;
	}

	public void put(X x, Y y, Z value) {
		Map<Y, Z> row = rows.get(x);
		if (row == null) {
			row = new TreeMap<Y, Z>();
			rows.put(x, row);
		}
		row.put(y, value);
		if (!columnNames.contains(y)) {
			columnNames.add(y);
			columnList.add(y);
		}
	}

	public void addColumn(Y y) {
		if (!columnNames.contains(y)) {
			columnNames.add(y);
			columnList.add(y);
		}
	}

	// �������ȡ���
	public Z get(X x, Y y) {
		if (x == null || y == null) {
			return null;
		}
		Map<Y, Z> row = rows.get(x);
		return row != null ? row.get(y) : null;
	}

	// �ϲ�����һ�ű�
	public void merge(RawTable<X, Y, Z> another) {
		for (Map.Entry<X, Map<Y, Z>> row : another.rows.entrySet()) {
			X x = row.getKey();
			for (Y y : another.columnNames) {
				Z value = row.getValue().get(y);
				if (value == null) {
					continue;
				} else {
					this.put(x, y, value);
				}
			}
		}
	}

	// ��ȡ�����е�����
	public Set<Y> getColumnNames() {
		return columnNames;
	}
	
	public void setColumnNames(Set<Y> columnNames){
		this.columnNames = columnNames;
	}

	public List<Y> getColumnList() {
		return columnList;
	}
	
	public void setColumnList(List<Y> columnList){
		this.columnList = columnList;
	}

	public Map<X, Map<Y, Z>> getRows() {
		return rows;
	}
	
	public void setRows(Map<X, Map<Y, Z>> rows){
		this.rows = rows;
	}

	public List<BufferedImage> getImages() {
		return images;
	}

	public void setImages(List<BufferedImage> images) {
		this.images = images;
	}
	
	public String getRowName() {
		return rowName;
	}
	
	public void setRowName(String rowName){
		this.rowName = rowName;
	}

	public Map<Y, Z> getRow(X key) {
		return rows.get(key);
	}

	public Set<X> getRowKeys() {
		return rows.keySet();
	}

	// ���key�б�(���ָ����orderBy,�ᰴ�ն�Ӧ�д���)
	public List<X> getRowKeyList() {
		if (orderBy == null) {
			return new ArrayList<X>(rows.keySet());
		}

		// �������rowKey����˳��ȡ��
		List<X> rows = new ArrayList<X>();
		for (Pair<String, X> pair : orderBy) {
			rows.add(pair.getRowKey());
		}
		return rows;
	}

	public boolean hasKey(X key) {
		return rows.containsKey(key);
	}
}
